/*
 * progress.h
 *
 *  Created on: Sep 19, 2018
 *      Author: ax
 */

#ifndef SOS_INC_PROGRESS_H_
#define SOS_INC_PROGRESS_H_

#include <Error.h>
#include <System.h>
#include <Process.h>


typedef Uint16 Process_Cnt;

//MUST always put in argv[0]
typedef struct {
    void* pls;      //progress local storage, just like TLS
    Name  name;
    void* stdio;
    Process_Hooks* hook;
}* Process_Env, Process_Environment;

typedef union __packed {
    Status                  val;
    struct {
        Status  run:  5;
        Status  cut:  2;
        Status  attr: 3;
        Status  rsvd: 6;  } fld;
} ProcessStatus;  //status

/* XXX DO KEEP sizeof(Process_ControlBlock) == 32, we may use it to optimizing the access speed;
 * 1st: kernel & monitor shared, prev/next used for merge queue's head / tail;
 * argv[0] / env: point to  Process_Env if argc != 0;
 * */
typedef struct Process_ControlBlock* Process_Handler;
typedef struct __packed Process_ControlBlock {
    Process_Handler     prev;   //timeout queue's last(it linked to a wait forever pend progress if exist)
    Process_Handler     next;   //timeout queue's head

    ProcessStatus       sts;
    Error_Number        eno;    //error number
    /* progress with lower priority can not cut behind a higher one, who is in cut status;
     * the lower one will cut next until it's not in cut OR with a lower priority. */
    Priority            pri;    //priority
    Sid                 pend;   //Object pend on
    SizeS               argc;   //!0 if used

    void*               argv;   //MUST always put Process_Env in argv[0] if argc is not 0
    Process             entry;  //entry

    Timestamp           to;     //timeout
} Process_ControlBlock;


#define Process_MERGE              ((Process_Id) 0)
#define Process_KERNEL             ((Process_Id) 0)
#define Process_MONITOR            ((Process_Id) 0)//really @ zero


//////////////////////API////////////////////////////
extern void Process_setup(void);
extern void Process_dispatch(void);
extern void Process_delayTimeoutReschedual(void);



////////////////////////////////////////////////////
static inline
Process_Handler
Process_nextTimeout(
    void
){//no valid check here, as it's called from a valid statement
    //return &Process_Pool[Process_Pool[0].next];
    TODO("");//TODO Process_nextTimeout
    return NULL;
}

static inline
Process_Handler
Process_next(
    Process_Handler cur
){
    return cur->next;
}


//static inline
//Process_Id
//Process_nextPid(
//    Process_Id pid
//){
//    if (0 == pid) pid = Sos.progress.current;
//    return Process_Pool[pid].next;
//}

static inline
Process_Handler
Process_previous(
    Process_Handler cur
){
    //Process_Id pid = cur->prev;
    //return pid ? &Process_Pool[pid] : NULL;
    TODO("");//TODO Process_previous

    return NULL;
}

static inline
bool
Process_haveMark(
    Process_Handler prog,
    Process_Status ps
){
    return prog->sts.val & ps;
}

static inline
void
Process_mark(
    Process_Handler prog,
    Process_Status ps
){
    prog->sts.val |= ps;
}

static inline
void
Process_demark(
    Process_Handler prog,
    Process_Status ps
){
    prog->sts.val &= ~ps;
}

//static inline
//Process_Id
//Process_getIdByPcb(
//    Process_Handler prog
//){
//    //return prog - &Process_Pool[0];
//}


static inline
Process_Handler
Process_delayPcbHead(
    void
){//TODO implement Process_delayPcbHead
    return NULL;
}

static inline
void
Process_remove(
    Process_Handler      prog
){
    prog->prev->next = prog->next;
    prog->next->prev = prog->prev;
    ;//? TODO set prog->next/prev to NULL
}

static inline
void
Process_safeInsert(
    Process_Handler      jumper,
    Process_Handler      queue
){
//    Process_Id aid = Process_getIdByPcb(jumper);
//
//    Process_Handler tmpPcb = &Process_Pool[queue->prev];
//    Process_Id tmpId = tmpPcb->next;
//    tmpPcb->next = aid;
//    jumper->next = tmpId;
//
//    tmpPcb = &Process_Pool[queue->next];
//    tmpId = tmpPcb->prev;
//    tmpPcb->prev = aid;
//    jumper->prev = tmpId;
}


static inline
void
Process_timeoutedReschedual(
    void
){
    Process_Handler prog = Process_nextTimeout();
    while (prog->to >= Timer_getStamp()) {
        Process_remove(prog);
        prog = Process_next(prog);
        if (NULL == prog) break;
    }
}

#endif /* SOS_INC_PROGRESS_H_ */
